import {
    Block,
    GameMode,
    Player,
    system,
    Vector3,
    world,
} from "@minecraft/server";
import { EventSubscription } from "@sapi-game/gameEvent/eventManager";
import { Game, GameComponent, GameState } from "@sapi-game/main";
import { Vector3Utils } from "@sapi-game/utils";
import { Algorithm } from "@sapi-game/utils/index";
import { EffectIds } from "@sapi-game/utils/vanila-data";
import { ParkourContext } from "@/parkour/parkourContext";

interface EffectBlockTask {
    block: Block;
    originalType: string;
    tempType: string;
    destroy: boolean; //是否用摧毁方式
    removeTick: number; // 多少 tick 后移除
    restoreTick: number; // 多少 tick 后恢复
    removed: boolean;
}

export class PKEffectBlockComponent extends GameComponent<
    GameState<any, ParkourContext>
> {
    private tasks = new Map<string, EffectBlockTask>();
    private sub: EventSubscription | null = null;

    effectBlocks: Record<string, (player: Player, block: Block) => void> = {
        "minecraft:black_wool": (p) => {
            if (p.getGameMode() == GameMode.Creative) {
                p.onScreenDisplay.setActionBar("你会死");
            } else {
                p.kill();
            }
        },
        "minecraft:lime_wool"(p) {
            p.addEffect(EffectIds.JumpBoost, 100, { amplifier: 2 });
        },
        "minecraft:light_blue_wool"(p) {
            p.addEffect(EffectIds.Speed, 100, { amplifier: 2 });
        },
        "minecraft:magenta_wool"(p) {
            p.addEffect(EffectIds.SlowFalling, 100, { amplifier: 1 });
        },
        "minecraft:orange_wool"(p) {
            p.addEffect(EffectIds.FireResistance, 100, { amplifier: 1 });
        },
        "minecraft:gray_wool"(p) {
            p.addEffect(EffectIds.Slowness, 100, { amplifier: 2 });
        },
        "minecraft:glass": (_, b) => {
            const key = this.serializePos(b.location);
            if (!this.tasks.has(key)) {
                this.tasks.set(key, {
                    block: b,
                    originalType: b.typeId,
                    destroy: true,
                    tempType: "minecraft:air",
                    removeTick: system.currentTick + 5,
                    restoreTick: system.currentTick + 25,
                    removed: false,
                });
            }
        },
    };

    targetBlocks: Record<string, (player: Player, block: Block) => void> = {
        "minecraft:black_stained_glass"(p, b) {
            if (p.getGameMode() == GameMode.Creative) {
                p.sendMessage("你会死");
            } else {
                p.kill();
            }
        },
        "minecraft:purple_stained_glass"(p, b) {
            const above = b.above();
            if (above && above.isAir) {
                p.teleport(above.center());
            }
        },
        "minecraft:magenta_stained_glass"(p) {
            p.addEffect(EffectIds.Levitation, 100, { amplifier: 1 });
        },
        "minecraft:white_stained_glass": (_, b) => {
            this.chainSet(b, {
                destroy: true,
                tempType: "minecraft:air",
                removeDelay: 0,
                restoreDelay: 100,
            });
        },
        "minecraft:lime_stained_glass": (_, b) => {
            this.chainSet(b, {
                destroy: false,
                tempType: "minecraft:slime",
                removeDelay: 0,
                restoreDelay: 100,
            });
        },
    };

    override onAttach(): void {
        //效果方块
        this.subscribe(Game.events.onBlock, (t) => {
            if (
                this.state.context.groupSet.findById(t.player.id) &&
                t.player.getGameMode() != GameMode.Spectator
            ) {
                this.effectBlocks[t.block.typeId]?.(t.player, t.block);
            }
        });
        //tick订阅
        this.sub =
            this.subscribe(Game.events.interval, this.onTick.bind(this)) ??
            null;
        //射击方块
        this.subscribe(world.afterEvents.projectileHitBlock, (t) => {
            if (!t.source) return;
            if (
                this.state.context.groupSet.findById(t.source.id) &&
                t.source instanceof Player &&
                t.source.getGameMode() != GameMode.Spectator
            ) {
                const hitBlock = t.getBlockHit();
                this.targetBlocks[hitBlock.block.typeId]?.(
                    t.source,
                    hitBlock.block
                );
            }
        });
    }

    /**连锁 */
    private chainSet(
        block: Block,
        config: {
            destroy: boolean;
            tempType: string;
            removeDelay: number;
            restoreDelay: number;
        }
    ) {
        const blocks = Algorithm.bfsBlocks(block, (b, d) => {
            return b.typeId == block.typeId;
        });
        for (let b of blocks) {
            const key = Vector3Utils.toString(b.location);
            if (!this.tasks.has(key)) {
                this.tasks.set(key, {
                    block: b,
                    originalType: b.typeId,
                    destroy: config.destroy,
                    tempType: config.tempType,
                    removeTick: system.currentTick + config.removeDelay,
                    restoreTick: system.currentTick + config.restoreDelay,
                    removed: false,
                });
            }
        }
    }

    private onTick() {
        const now = system.currentTick;
        for (const [key, task] of this.tasks) {
            const block = task.block;
            if (!block?.dimension) {
                this.tasks.delete(key);
                continue;
            }

            if (!task.removed && now >= task.removeTick) {
                if (task.destroy) {
                    block.dimension.runCommand(
                        `setblock ${Vector3Utils.toArray(block.location).join(
                            " "
                        )} ${task.tempType} destroy`
                    );
                } else {
                    block.setType(task.tempType);
                }
                task.removed = true;
            } else if (task.removed && now >= task.restoreTick) {
                // 恢复方块
                block.setType(task.originalType);
                this.tasks.delete(key);
            }
        }
    }

    override onDetach(): void {
        if (this.sub) this.unsubscribe(this.sub);
        this.restoreAllBlocks();
        super.onDetach();
    }

    /** 恢复所有被替换的方块 */
    restoreAllBlocks() {
        for (const [key, task] of this.tasks) {
            const block = task.block;
            if (block?.dimension) {
                block.setType(task.originalType);
            }
            this.tasks.delete(key);
        }
    }

    /** 序列化坐标作为 map key */
    private serializePos(loc: Vector3): string {
        return `${Math.floor(loc.x)},${Math.floor(loc.y)},${Math.floor(loc.z)}`;
    }
}
